#pragma once

#include <string>

#include "os_socket.h"

namespace qio {

struct IPAddress {
  std::string addr;
  std::uint16_t port;

  IPAddress() QIO_NOEXCEPT;

  IPAddress(const std::string &, std::uint16_t) QIO_NOEXCEPT;

  std::string ToString() const QIO_NOEXCEPT;
};

inline int SetReuseAddr(Fd fd) QIO_NOEXCEPT {
  auto v = 1;
  return socket_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                           reinterpret_cast<void *>(&v), sizeof(v));
}

inline int SetReusePort(Fd fd) QIO_NOEXCEPT {
#if !defined(__WIN__)
  auto v = 1;
  return socket_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
                           reinterpret_cast<void *>(&v), sizeof(v));
#else
  return 0;
#endif
}

inline int SetKeepAlive(Fd fd, bool enable) QIO_NOEXCEPT {
  auto v = enable ? 1 : 0;
  return socket_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
                           reinterpret_cast<void *>(&v), sizeof(v));
}

inline int SetTcpNoDelay(Fd fd, bool enable) QIO_NOEXCEPT {
  auto v = enable ? 1 : 0;
  return socket_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
                           reinterpret_cast<void *>(&v), sizeof(v));
}

extern int SetTimeout(Fd fd, std::size_t timeout_ms) QIO_NOEXCEPT;

// addr 转换为 字符串
extern IPAddress ParseSockAddrName4(const struct sockaddr_in *addr)
    QIO_NOEXCEPT;

// 生成 sockaddr_in
extern int IPNameToSockAddr4(const std::string &name, std::uint16_t port,
                             struct sockaddr_in *out_addr) QIO_NOEXCEPT;

template <typename R, typename P>
inline int SetTimeout(Fd fd, std::chrono::duration<R, P> timeout) QIO_NOEXCEPT {
  auto ms_timeout =
      std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
  return SetTimeout(fd, static_cast<size_t>(ms_timeout.count()));
}

}  // namespace qio